/*
 * colortf.c
 *
 *  Created on: Mar 17, 2021
 *      Author: kychu
 */

#include "colortf.h"

/**
 * @brief Simple helper function, converting HSV color space to RGB color space
 *
 * Wiki: https://en.wikipedia.org/wiki/HSL_and_HSV
 *
 */
void hsv2rgb(led_hsv_t *hsv, led_rgb_t *rgb)
{
  hsv->h %= 360; // h -> [0,360]
  uint16_t rgb_max = hsv->v * 2.55f;
  uint16_t rgb_min = rgb_max * (100 - hsv->s) / 100.0f;

  uint16_t i = hsv->h / 60;
  uint16_t diff = hsv->h % 60;

  // RGB adjustment amount by hue
  uint16_t rgb_adj = (rgb_max - rgb_min) * diff / 60;

  switch (i) {
    case 0:
      rgb->r = rgb_max;
      rgb->g = rgb_min + rgb_adj;
      rgb->b = rgb_min;
    break;
    case 1:
      rgb->r = rgb_max - rgb_adj;
      rgb->g = rgb_max;
      rgb->b = rgb_min;
    break;
    case 2:
      rgb->r = rgb_min;
      rgb->g = rgb_max;
      rgb->b = rgb_min + rgb_adj;
    break;
    case 3:
      rgb->r = rgb_min;
      rgb->g = rgb_max - rgb_adj;
      rgb->b = rgb_max;
    break;
    case 4:
      rgb->r = rgb_min + rgb_adj;
      rgb->g = rgb_min;
      rgb->b = rgb_max;
    break;
    default:
      rgb->r = rgb_max;
      rgb->g = rgb_min;
      rgb->b = rgb_max - rgb_adj;
    break;
  }
}

void rgb2hsv(led_rgb_t *rgb, led_hsv_t *hsv)
{
  uint8_t rgb_min = ((rgb->r > rgb->g) ? rgb->g : rgb->r);
  uint8_t rgb_max = ((rgb->r > rgb->g) ? rgb->r : rgb->g);
  rgb_min = (rgb_min > rgb->b) ? rgb->b : rgb_min;
  rgb_max = (rgb_max > rgb->b) ? rgb_max : rgb->b;

  hsv->v = 100 * rgb_max / 255; // [0, 100]

  if(rgb_max == rgb_min) {
    // black-gray-white
    hsv->h = 0;
    hsv->s = 0;
  } else {
    // colors other than black-gray-white
    uint16_t d = (rgb->r == rgb_min) ? rgb->g - rgb->b : \
                ((rgb->b == rgb_min) ? rgb->r - rgb->g : rgb->b - rgb->r);
    uint16_t h = (rgb->r == rgb_min) ? 3 : ((rgb->b == rgb_min) ? 1 : 5);
    hsv->h = 60 * (h - 255 * d / (rgb_max - rgb_min));
    hsv->s = 100 * (rgb_max - rgb_min) / rgb_max;
  }
}
